﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#include "GLTexture.h"
#include "GLFrameBuffer.h"
#include "../../Math/ImageUtils.h"

namespace UX_STL
{
namespace GLShell
{
	using namespace UXMathExt;

	
//-------------------------- GLSamplerSW --------------------------//
/*
=================================================
	установить сэмплер для текстуры
=================================================
*/
	bool GLSamplerSW::Apply(const GLTexture *pTex) const
	{
		return pTex->ApplySampler( _sSrc );
	}
	


//--------------------------- GLSampler ---------------------------//
/*
=================================================
	установить сэмплер для текстуры
=================================================
*/
	bool GLSampler::Apply(const GLTexture *pTex) const
	{
		return pTex->ApplySampler( _sSrc );
	}



//--------------------------- GLTexture ---------------------------//
/*
=================================================
	конструктор
=================================================
*/
	GLTexture::GLTexture(gl_texture::type eTarget):
		_eTarget(eTarget), _uID(0), _bImageSupported(false), _bCompressed(false),
		_uMaxLevel(-1), _bRenderable(false)
	{
	}

/*
=================================================
	деструктор
=================================================
*/
	GLTexture::~GLTexture()
	{
		if ( _uID != 0 )
		{
			GLOM()->DeleteTextures( 1, &_uID );
			_uID = 0;
		}
	}
	
/*
=================================================
	присоединить к кадровому буферу
	(присоединяет все слои массива!
	 в отличии от переопределенных функций)
=================================================
*/
	void GLTexture::Attach(GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel, uint uLayer)
	{
		pFBO->Attach( *this, eAttach, uLevel );
	}

/*
=================================================
	заглушки
=================================================
*/
	bool GLTexture::Storage(gl_rt_format::type eIFormat, const uvec3 &vDim, uint uLevels, uint8) { RETURN_ERR("unsupported function"); }
	bool GLTexture::CreateLevel(uint uLevel, gl_tex_iformat::type eIFormat) { RETURN_ERR("unsupported function"); }
	bool GLTexture::SetImage(gl_tex_iformat::type eIFormat, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel) { RETURN_ERR("unsupported function"); }
	bool GLTexture::SubImage(const uvec3 &vOffset, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel) { RETURN_ERR("unsupported function"); }
	bool GLTexture::SetCompressedImage(gl_tex_iformat::type eIFormat, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel) { RETURN_ERR("unsupported function"); }
	bool GLTexture::CompressedSubImage(gl_tex_iformat::type eFormat, const uvec3 &vOffset, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel) { RETURN_ERR("unsupported function"); }
	
/*
=================================================
	возвращает размер возвращаемой текстуры
=================================================
*/
	bool GLTexture::GetImageSize(usize &uSize, gl_pixel_format::type eFormat, gl_pixel::type eType, uint uLevel)
	{
		CHECK_ERR( _eTarget != gl_texture::TEXTURE_2DMS and
					 _eTarget != gl_texture::TEXTURE_2DMS_ARRAY and
					 "multisampled textures not supported" );

		uint	bpp = 0;
		CHECK_ERR( GLTexFormatInfo::GetBitPerPixel( eFormat, eType, bpp ) );

		uvec3	dim = _vDimension;

		if ( _eTarget == gl_texture::TEXTURE_1D )
			dim.y = 1;

		if ( _eTarget == gl_texture::TEXTURE_1D or
			 _eTarget == gl_texture::TEXTURE_1D_ARRAY or
			 _eTarget == gl_texture::TEXTURE_2D or
			 _eTarget == gl_texture::TEXTURE_CUBE_MAP )
		{
			dim.z = 1;
		}
		uSize = ( (dim >> uLevel).Sum() * bpp ) >> 3;
		return true;
	}

/*
=================================================
	возвращает текстуру
=================================================
*/
	bool GLTexture::GetImage(void *pData, gl_pixel_format::type eFormat, gl_pixel::type eType, uint uLevel, gl_cube_face::type eFace)
	{
		CHECK_ERR( uLevel > _uMaxLevel );

		GLenum	target = _eTarget;

		if ( target == gl_texture::TEXTURE_CUBE_MAP )
		{
			target = eFace;
			CHECK_ERR( eFace >= gl_cube_face::_FIRST and eFace <= gl_cube_face::_LAST );
		}
		else
			ASSERT( eFace == gl_cube_face::_UNKNOWN and "cube face parameter not used" );
		
		GL_CALL_R( glGetTextureImage( _uID, target, uLevel, eFormat, eType, pData ) );
		return true;
	}
	
/*
=================================================
	возвращает размер сжатой текстуры
=================================================
*/
	bool GLTexture::GetCompressedImageSize(usize &uSize, uint uLevel)
	{
		GLenum	target	= _eTarget;
		GLint	size	= 0;

		if ( _eTarget == gl_texture::TEXTURE_CUBE_MAP )
			target = gl_cube_face::_FIRST;

		GL_CALL_R( glGetTextureLevelParameteriv( _uID, target, uLevel, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &size ) );
		return true;
	}
	
/*
=================================================
	возвращает сжатую текстуру
=================================================
*/
	bool GLTexture::GetCompressedImage(void *pData, uint uLevel, gl_cube_face::type eFace)
	{
		GLenum	target = _eTarget;

		if ( _eTarget == gl_texture::TEXTURE_CUBE_MAP )
		{
			CHECK_ERR( eFace >= gl_cube_face::_FIRST and eFace <= gl_cube_face::_LAST );
			target = eFace;
		}

		GL_CALL_R( glGetCompressedTextureImage( _uID, target, uLevel, pData ) );
		return true;
	}

/*
=================================================
	возвращает текстуру
=================================================
*/
	bool GLTexture::CopyImage(const GLTexture *pFromTex, uint uReadLevel, const uvec3 &vReadOffset, uint uWriteLevel, const uvec3 &vWriteOffset, const uvec3 &vSize)
	{
		CHECK_ERR( glGetContext().IsValid( glCopyImageSubData ) );

		GLenum	read_target		= pFromTex->Target(),
				write_target	= _eTarget;

		if ( read_target == gl_texture::TEXTURE_CUBE_MAP )
		{
			read_target = vReadOffset.z >= gl_cube_face::_FIRST  ?  vReadOffset.z  :  gl_cube_face::_FIRST + vReadOffset.z;
			CHECK_ERR( read_target >= gl_cube_face::_FIRST and read_target <= gl_cube_face::_LAST );
		}
		
		if ( write_target == gl_texture::TEXTURE_CUBE_MAP )
		{
			write_target = vWriteOffset.z >= gl_cube_face::_FIRST  ?  vWriteOffset.z  :  gl_cube_face::_FIRST + vWriteOffset.z;
			CHECK_ERR( write_target >= gl_cube_face::_FIRST and write_target <= gl_cube_face::_LAST );
		}

		GL_CALL_R( glCopyImageSubData( pFromTex->Id(), read_target, uReadLevel, vReadOffset.x, vReadOffset.y, vReadOffset.z,
										Id(), write_target, uWriteLevel, vWriteOffset.x, vWriteOffset.y, vWriteOffset.z,
										vSize.x, vSize.y, vSize.z ) );
		return true;
	}
	
/*
=================================================
	копирует изображение с экрана в текстуру
=================================================
*/
	bool GLTexture::CopyScreen(const urect &sScreenSize, const uvec3 &vOffset, uint uLevel)
	{
		switch ( _eTarget )
		{
			case gl_texture::TEXTURE_1D :
				GL_CALL_R( glCopyTextureSubImage1D( _uID, _eTarget, uLevel, vOffset.x, sScreenSize.left, sScreenSize.bottom, sScreenSize.right ) );
				return true;

			case gl_texture::TEXTURE_1D_ARRAY :
			case gl_texture::TEXTURE_2D :
				GL_CALL_R( glCopyTextureSubImage2D( _uID, _eTarget, uLevel, vOffset.x, vOffset.y,
													sScreenSize.left, sScreenSize.bottom, sScreenSize.right, sScreenSize.top ) );
				return true;

			case gl_texture::TEXTURE_CUBE_MAP :
			{
				uint face = vOffset.z >= gl_cube_face::_FIRST  ?  vOffset.z  :  gl_cube_face::_FIRST + vOffset.z;
				CHECK_ERR( face >= gl_cube_face::_FIRST and face <= gl_cube_face::_LAST );

				GL_CALL_R( glCopyTextureSubImage2D( _uID, face, uLevel, vOffset.x, vOffset.y,
													sScreenSize.left, sScreenSize.bottom, sScreenSize.right, sScreenSize.top ) );
				return true;
			}
			case gl_texture::TEXTURE_2D_ARRAY :
			case gl_texture::TEXTURE_3D :
				GL_CALL_R( glCopyTextureSubImage3D( _uID, _eTarget, uLevel, vOffset.x, vOffset.y, vOffset.z,
													sScreenSize.left, sScreenSize.bottom, sScreenSize.right, sScreenSize.top ) );
				return true;
		}
		RETURN_ERR( "unsupported texture type" );
	}

/*
=================================================
	удалить текстуру
=================================================
*/
	void GLTexture::Destroy()
	{
		if ( _uID != 0 )
		{
			GLOM()->DeleteTextures( 1, &_uID );
			_uID = 0;
		}

		_cSampler.Destroy();
		
		_vDimension			= uvec3();
		_eIFormat			= gl_rt_format::_UNKNOWN;
		_sSwizzle			= GLTexSwizzle();
		_bImageSupported	= false;
		_bCompressed		= false;
		_uMaxLevel			= uint16(-1);
	}

/*
=================================================
	устанавливает новый формат каналов цвета
=================================================
*/
	bool GLTexture::SetSwizzle(GLTexSwizzle sSwizzle)
	{
		CHECK_ERR( C_GL_ARB_texture_swizzle );

		GLint	a_swizzle[4] = {0};
		sSwizzle.ToArray( a_swizzle );

		GL_CALL_R( glTextureParameteriv( _uID, _eTarget, GL_TEXTURE_SWIZZLE_RGBA, a_swizzle ) );
		_sSwizzle = sSwizzle;
		return true;
	}

/*
=================================================
	устанавливает сэмплер
=================================================
*/
	bool GLTexture::SetSampler(const GLSamplerSrc &sSrc)
	{
		CHECK_ERR( _cSampler.Create( sSrc ) );
		CHECK_ERR( _cSampler.Apply( this ) );
		return true;
	}
	
/*
=================================================
	устанавливает сэмплер по умолчанию для текстуры
=================================================
*/
	bool GLTexture::ApplySampler(const GLSamplerSrc &sSrc) const
	{
		// TODO: check
		///CHECK_ERR( (_eTarget == gl_texture::TEXTURE_2D_MULTISAMPLE or
		//				_eTarget == gl_texture::TEXTURE_2D_MULTISAMPLE_ARRAY) and
		//				"not supported for multisample textures" );

		bool	ret = true;
		GL_CALL_BA( glTextureParameterf( _uID, _eTarget, GL_TEXTURE_LOD_BIAS, sSrc.fLodBias ), ret );
		GL_CALL_BA( glTextureParameteri( _uID, _eTarget, GL_TEXTURE_MIN_LOD, sSrc.vLOD.x ), ret );
		GL_CALL_BA( glTextureParameteri( _uID, _eTarget, GL_TEXTURE_MAX_LOD, sSrc.vLOD.y ), ret );
		GL_CALL_BA( glTextureParameteri( _uID, _eTarget, GL_TEXTURE_WRAP_S, sSrc.sWrap.s ), ret );
		GL_CALL_BA( glTextureParameteri( _uID, _eTarget, GL_TEXTURE_WRAP_T, sSrc.sWrap.t ), ret );
		GL_CALL_BA( glTextureParameteri( _uID, _eTarget, GL_TEXTURE_WRAP_R, sSrc.sWrap.r ), ret );
		GL_CALL_BA( glTextureParameteri( _uID, _eTarget, GL_TEXTURE_MIN_FILTER, sSrc.sFilter.min ), ret );
		GL_CALL_BA( glTextureParameteri( _uID, _eTarget, GL_TEXTURE_MAG_FILTER, sSrc.sFilter.mag ), ret );
		GL_CALL_BA( glTextureParameteri( _uID, _eTarget, GL_TEXTURE_COMPARE_MODE, sSrc.eCompareRTT == GL_NONE ? GL_NONE : GL_COMPARE_REF_TO_TEXTURE ), ret );
		
		if ( sSrc.eCompareRTT != GL_NONE )
			GL_CALL_BA( glTextureParameteri( _uID, _eTarget, GL_TEXTURE_COMPARE_FUNC, sSrc.eCompareRTT ), ret );
		
		if ( C_GL_EXT_texture_filter_anisotropic and sSrc.uAnisotropy > 0 )
			GL_CALL_BA( glTextureParameteri( _uID, _eTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, sSrc.uAnisotropy ), ret );

		return ret;
	}

/*
=================================================
	возвращает информацию о текстуре и заданном
	уровне текстуры
=================================================
*/
	bool GLTexture::GetTextureInfo(GLTextureInfo &sInfo, uint uLevel, gl_cube_face::type eFace) const
	{
		typedef GLTextureInfo::EType	EType;

		bool	ret			= true;
		int		temp		= 0;
		GLenum	e_target	= _eTarget == gl_texture::TEXTURE_CUBE_MAP ? eFace : _eTarget;
		
		// TODO: check
		//if ( _eTarget == gl_texture::TEXTURE_2D_MULTISAMPLE or
		//	 _eTarget == gl_texture::TEXTURE_2D_MULTISAMPLE_ARRAY )
		//{
			GL_CALL_BA( glGetTextureLevelParameteriv( _uID, _eTarget, uLevel, GL_TEXTURE_SAMPLES, (GLint *)& sInfo.uSamples ), ret );
			GL_CALL_BA( glGetTextureLevelParameteriv( _uID, _eTarget, uLevel, GL_TEXTURE_FIXED_SAMPLE_LOCATIONS, &temp ), ret );
			sInfo.bFixedSampleLocation = (temp == GL_TRUE);
		//}
		//else
		//{
			GL_CALL_BA( glGetTextureParameteriv( _uID, _eTarget, GL_TEXTURE_MIN_LOD,		(GLint *)& sInfo.vLOD.x ), ret );
			GL_CALL_BA( glGetTextureParameteriv( _uID, _eTarget, GL_TEXTURE_MAX_LOD,		(GLint *)& sInfo.vLOD.y ), ret );
			GL_CALL_BA( glGetTextureParameteriv( _uID, _eTarget, GL_TEXTURE_BASE_LEVEL,		& sInfo.iBaseLevel ), ret );
			GL_CALL_BA( glGetTextureParameteriv( _uID, _eTarget, GL_TEXTURE_COMPARE_MODE,	& temp ), ret );
		
			if ( temp == GL_TRUE ) {
				GL_CALL_BA( glGetTextureParameteriv( _uID, _eTarget, GL_TEXTURE_COMPARE_FUNC,	& temp ), ret );
				sInfo.eCompareRTT = (gl_compare::type)temp;
			}

			GL_CALL_BA( glGetTextureParameteriv( _uID, _eTarget, GL_TEXTURE_IMMUTABLE_FORMAT,	& temp ), ret );
			sInfo.bImmutable = (temp == GL_TRUE);
		//}
		

		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_WIDTH,			(GLint *)& sInfo.vDimension.x ), ret );
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_HEIGHT,		(GLint *)& sInfo.vDimension.y ), ret );
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_DEPTH,			(GLint *)& sInfo.vDimension.z ), ret );
		
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_INTERNAL_FORMAT, & temp ), ret );
		sInfo.eIFormat = (gl_tex_iformat::type) temp;

		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_RED_SIZE,		(GLint *)& sInfo.aCompSize[EType::R] ), ret );
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_GREEN_SIZE,	(GLint *)& sInfo.aCompSize[EType::G] ), ret );
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_BLUE_SIZE,		(GLint *)& sInfo.aCompSize[EType::B] ), ret );
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_ALPHA_SIZE,	(GLint *)& sInfo.aCompSize[EType::A] ), ret );
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_DEPTH_SIZE,	(GLint *)& sInfo.aCompSize[EType::DEPTH] ), ret );
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_STENCIL_SIZE,	(GLint *)& sInfo.aCompSize[EType::STENCIL] ), ret );
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_SHARED_SIZE,	(GLint *)& sInfo.aCompSize[EType::SHARED] ), ret );

		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_RED_TYPE,		(GLint *)& sInfo.aCompType[EType::R] ), ret );
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_GREEN_TYPE,	(GLint *)& sInfo.aCompType[EType::G] ), ret );
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_BLUE_TYPE,		(GLint *)& sInfo.aCompType[EType::B] ), ret );
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_ALPHA_TYPE,	(GLint *)& sInfo.aCompType[EType::A] ), ret );
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, e_target, uLevel, GL_TEXTURE_DEPTH_TYPE,	(GLint *)& sInfo.aCompType[EType::DEPTH] ), ret );
		sInfo.aCompType[EType::STENCIL]	= gl_tex_component::INT;
		sInfo.aCompType[EType::SHARED]	= gl_tex_component::NONE;
		
		GL_CALL_BA( glGetTextureLevelParameteriv( _uID, _eTarget, uLevel, GL_TEXTURE_COMPRESSED,	&temp ), ret );
		sInfo.bCompressed = (temp == GL_TRUE);

		return ret;
	}


	
//-------------------------- GLTexture2D --------------------------//
/*
=================================================
	конструктор
=================================================
*/
	GLTexture2D::GLTexture2D(): GLTexture(gl_texture::TEXTURE_2D)
	{
	}
	
/*
=================================================
	присоединить к кадровому буферу
=================================================
*/
	void GLTexture2D::Attach(GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel, uint uLayer)
	{
		ASSERT( !_bCompressed and "can't render to compressed texture" );
		pFBO->Attach2D( *this, eAttach, uLevel );
	}
	
/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTexture2D::Create(gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples)
	{
		CHECK_ERR( (vDim.x != 0 or vDim.y != 0) and vDim.z == 0 );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_TEXTURE_SIZE );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );

		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );

		gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
		gl_pixel::type			e_type	= gl_pixel::UBYTE;
		GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

		GL_CALL_R( glTextureImage2D( _uID, _eTarget, 0, eIFormat, vDim.x, vDim.y, 0, e_fmt, e_type, null ) );
		
		_vDimension	= uvec3( vDim.xy(), 0 );
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		SetBaseLevel( 0 );
		GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}
	
/*
=================================================
	создать uLevels уровней
=================================================
*/
	bool GLTexture2D::Storage(gl_rt_format::type eIFormat, const uvec3 &vDim, uint uLevels, uint8)
	{
		const uint	u_max_levels = GetNumberOfMipmaps( vDim ) + 1;
		
		CHECK_ERR( (vDim.x != 0 or vDim.y != 0) and vDim.z == 0 );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_TEXTURE_SIZE );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );
		CHECK_ERR( uLevels <= u_max_levels );

		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );

		if ( uLevels == 0 )
			uLevels = u_max_levels;

		if ( C_GL_ARB_texture_storage )
		{
			GL_CALL_R( glTextureStorage2D( _uID, _eTarget, eIFormat, uLevels, vDim.x, vDim.y ) );
		}
		else
		{
			gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
			gl_pixel::type			e_type	= gl_pixel::UBYTE;
			GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

			for (uint i = 0; i < uLevels; ++i)
			{
				GL_CALL_R( glTextureImage2D( _uID, _eTarget, i, eIFormat,
											 Max( vDim.x >> i, 1u ), Max( vDim.y >> i, 1u ), 0,
											 e_fmt, e_type, null ) );
			}
		}
		
		_vDimension	= uvec3( vDim.xy(), 0 );
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		SetBaseLevel( 0 );
		GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}
	
/*
=================================================
	создать уровень
=================================================
*/
	bool GLTexture2D::CreateLevel(uint uLevel, gl_tex_iformat::type eIFormat)
	{
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension ) );
		CHECK_ERR( _uID != 0 );

		if ( eIFormat == gl_tex_iformat::_UNKNOWN )
			eIFormat = _eIFormat;
		
		gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
		gl_pixel::type			e_type	= gl_pixel::UBYTE;
		GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

		GL_CALL_R( glTextureImage2D( _uID, _eTarget, uLevel, eIFormat,
									 Max( _vDimension.x >> uLevel, 1u ),
									 Max( _vDimension.y >> uLevel, 1u ), 0,
									 e_fmt, e_type, null ) );

		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool GLTexture2D::SetImage(gl_tex_iformat::type eIFormat, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel)
	{
		CHECK_ERR( (vDim.x != 0 or vDim.y != 0) and vDim.z == 0 );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_TEXTURE_SIZE );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );

		bool	b_created = false;

		if ( _uID == 0 )
		{
			CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
			b_created = true;
		}

		GL_CALL_R( glTextureImage2D( _uID, _eTarget, uLevel, eIFormat, vDim.x, vDim.y, 0, eFormat, eType, pData ) );
		

		if ( b_created )
		{
			_vDimension	= uvec3( vDim.xy() << uLevel, 0 );
			_eIFormat	= eIFormat;
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
			GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );
		}
		else
		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool GLTexture2D::SubImage(const uvec3 &vOffset, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel)
	{
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension ) );
		CHECK_ERR( (vDim.x != 0 or vDim.y != 0) and vDim.z == 0 );
		CHECK_ERR( _uID != 0 );

		GL_CALL_R( glTextureSubImage2D( _uID, _eTarget, uLevel, vOffset.x, vOffset.y, vDim.x, vDim.y, eFormat, eType, pData ) );
		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool GLTexture2D::SetCompressedImage(gl_tex_iformat::type eIFormat, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel)
	{
		CHECK_ERR( (vDim.x != 0 or vDim.y != 0) and vDim.z == 0 );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_TEXTURE_SIZE );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );
		
		bool	b_created = false;

		if ( _uID == 0 )
		{
			CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
			b_created = true;
		}

		GL_CALL_R( glCompressedTextureImage2D( _uID, _eTarget, uLevel, eIFormat, vDim.x, vDim.y, 0, (GLsizei)uDataSize, pData ) );
		
		if ( b_created )
		{
			_vDimension	= uvec3( vDim.xy() << uLevel, 0 );
			_eIFormat	= eIFormat;
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
			GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );
		}
		else
		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool GLTexture2D::CompressedSubImage(gl_tex_iformat::type eIFormat, const uvec3 &vOffset, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel)
	{
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension ) );
		CHECK_ERR( (vDim.x != 0 or vDim.y != 0) and vDim.z == 0 );
		CHECK_ERR( _uID != 0 );

		if ( eIFormat == gl_tex_iformat::_UNKNOWN and _bCompressed )
			eIFormat = _eIFormat;

		GL_CALL_R( glCompressedTextureSubImage2D( _uID, _eTarget, uLevel, vOffset.x, vOffset.y, vDim.x, vDim.y,
												  eIFormat, (GLsizei)uDataSize, pData ) );
		return true;
	}
	


//------------------------- GLTextureCube -------------------------//
/*
=================================================
	конструктор
=================================================
*/
	GLTextureCube::GLTextureCube(): GLTexture(gl_texture::TEXTURE_CUBE_MAP)
	{
	}

/*
=================================================
	присоединить к кадровому буферу
=================================================
*/
	void GLTextureCube::Attach(GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel, uint uLayer)
	{
		ASSERT( !_bCompressed and "can't render to compressed texture" );
		pFBO->AttachFace( *this, eAttach, gl_cube_face::_FIRST + uLayer, uLevel );
	}

/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTextureCube::Create(gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples)
	{
		CHECK_ERR( (vDim.x != 0 or vDim.y != 0) and vDim.z == 0 );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );

		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
		
		gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
		gl_pixel::type			e_type	= gl_pixel::UBYTE;
		GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

		for (uint t = gl_cube_face::_FIRST; t <= gl_cube_face::_LAST; ++t)
		{
			GL_CALL_R( glTextureImage2D( _uID, t, 0, eIFormat, vDim.x, vDim.y, 0, e_fmt, e_type, null ) );
		}

		_vDimension	= uvec3( vDim.xy(), 6 );
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		SetBaseLevel( 0 );
		GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}

/*
=================================================
	создать uLevels уровней текстуры
=================================================
*/
	bool GLTextureCube::Storage(gl_rt_format::type eIFormat, const uvec3 &vDim, uint uLevels, uint8)
	{
		const uint	u_max_levels = GetNumberOfMipmaps( vDim.xy() ) + 1;
		
		CHECK_ERR( (vDim.x != 0 or vDim.y != 0) and vDim.z == 0 );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );
		CHECK_ERR( uLevels <= u_max_levels );

		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );

		if ( uLevels == 0 )
			uLevels = u_max_levels;

		if ( C_GL_ARB_texture_storage )
		{
			GL_CALL_R( glTextureStorage2D( _uID, _eTarget, eIFormat, uLevels, vDim.x, vDim.y ) );
		}
		else
		{
			gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
			gl_pixel::type			e_type	= gl_pixel::UBYTE;
			GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

			for (uint t = gl_cube_face::_FIRST; t <= gl_cube_face::_LAST; ++t)
			{
				for (uint i = 0; i < uLevels; ++i)
				{
					GL_CALL_R( glTextureImage2D( _uID, t, i, eIFormat,
												 Max( vDim.x >> i, 1u ), Max( vDim.y >> i, 1u ), 0,
												 e_fmt, e_type, null ) );
				}
			}
		}
		
		_vDimension	= uvec3( vDim.xy(), 6 );
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		SetBaseLevel( 0 );
		GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}

/*
=================================================
	создать уровень текстуры
=================================================
*/
	bool GLTextureCube::CreateLevel(uint uLevel, gl_tex_iformat::type eIFormat)
	{
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension.xy() ) );
		CHECK_ERR( _uID != 0 );

		if ( eIFormat == gl_tex_iformat::_UNKNOWN )
			eIFormat = _eIFormat;
		
		gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
		gl_pixel::type			e_type	= gl_pixel::UBYTE;
		GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

		for (uint t = gl_cube_face::_FIRST; t <= gl_cube_face::_LAST; ++t)
		{
			GL_CALL_R( glTextureImage2D( _uID, t, uLevel, eIFormat,
										 Max( _vDimension.x >> uLevel, 1u ),
										 Max( _vDimension.y >> uLevel, 1u ), 0,
										 e_fmt, e_type, null ) );
		}

		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}

/*
=================================================
	
=================================================
*/
	bool GLTextureCube::SetImage(gl_tex_iformat::type eIFormat, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel)
	{
		CHECK_ERR( (vDim.x != 0 or vDim.y != 0) );
		CHECK_ERR( (vDim.z >= 0 and vDim.z <= 5) or
						(vDim.z >= gl_cube_face::_FIRST and vDim.z <= gl_cube_face::_LAST ) );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );

		bool	b_created	= false;
		GLenum	e_target	= vDim.z <= 5  ?  gl_cube_face::_FIRST + vDim.z  :  vDim.z;

		if ( _uID == 0 )
		{
			CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
			b_created = true;
		}

		GL_CALL_R( glTextureImage2D( _uID, e_target, uLevel, eIFormat, vDim.x, vDim.y, 0, eFormat, eType, pData ) );

		if ( b_created )
		{
			_vDimension	= uvec3( vDim.xy() << uLevel, 6 );
			_eIFormat	= eIFormat;
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
			GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );
		}
		else
		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}

/*
=================================================
	
=================================================
*/
	bool GLTextureCube::SubImage(const uvec3 &vOffset, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel)
	{
		CHECK_ERR( vOffset.z == 0 );
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension.xy() ) );
		CHECK_ERR( (vDim.z >= 0 and vDim.z <= 5) or
						(vDim.z >= gl_cube_face::_FIRST and vDim.z <= gl_cube_face::_LAST ) );
		CHECK_ERR( _uID != 0 );
		
		GLenum	e_target = vDim.z <= 5  ?  gl_cube_face::_FIRST + vDim.z  :  vDim.z;
		GL_CALL_R( glTextureSubImage2D( _uID, e_target, uLevel, vOffset.x, vOffset.y, vDim.x, vDim.y, eFormat, eType, pData ) );
		return true;
	}

/*
=================================================
	
=================================================
*/
	bool GLTextureCube::SetCompressedImage(gl_tex_iformat::type eIFormat, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel)
	{
		CHECK_ERR( (vDim.x != 0 or vDim.y != 0) and vDim.z == 0 );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );
		
		bool	b_created	= false;
		GLenum	e_target	= vDim.z <= 5  ?  gl_cube_face::_FIRST + vDim.z  :  vDim.z;

		if ( _uID == 0 )
		{
			CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
			b_created = true;
		}
		
		GL_CALL_R( glCompressedTextureImage2D( _uID, e_target, uLevel, eIFormat, vDim.x, vDim.y, 0, (GLsizei)uDataSize, pData ) );
		
		if ( b_created )
		{
			_vDimension	= uvec3( vDim.xy() << uLevel, 6 );
			_eIFormat	= eIFormat;
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
			GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );
		}
		else
		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}

/*
=================================================
	
=================================================
*/
	bool GLTextureCube::CompressedSubImage(gl_tex_iformat::type eIFormat, const uvec3 &vOffset, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel)
	{
		CHECK_ERR( vOffset.z == 0 );
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension.xy() ) );
		CHECK_ERR( (vDim.z >= 0 and vDim.z <= 5) or
						(vDim.z >= gl_cube_face::_FIRST and vDim.z <= gl_cube_face::_LAST ) );
		CHECK_ERR( _uID != 0 );

		if ( eIFormat == gl_tex_iformat::_UNKNOWN and _bCompressed )
			eIFormat = _eIFormat;
		
		GLenum	e_target = vDim.z <= 5  ?  gl_cube_face::_FIRST + vDim.z  :  vDim.z;
		GL_CALL_R( glCompressedTextureSubImage2D( _uID, e_target, uLevel, vOffset.x, vOffset.y, vDim.x, vDim.y,
												  eIFormat, (GLsizei)uDataSize, pData ) );
		return true;
	}

	
	
//------------------------ GLTexture2DArray -----------------------//
/*
=================================================
	конструктор
=================================================
*/
	GLTexture2DArray::GLTexture2DArray(): GLTexture(gl_texture::TEXTURE_2D_ARRAY)
	{
	}
	
/*
=================================================
	присоединить к кадровому буферу
=================================================
*/
	void GLTexture2DArray::Attach(GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel, uint uLayer)
	{
		ASSERT( !_bCompressed and "can't render to compressed texture" );
		pFBO->AttachLayer( *this, eAttach, uLayer, uLevel );
	}
	
/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTexture2DArray::Create(gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples)
	{
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_ARRAY_TEXTURE_LAYERS );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );

		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
		
		gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
		gl_pixel::type			e_type	= gl_pixel::UBYTE;
		GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

		GL_CALL_R( glTextureImage3D( _uID, _eTarget, 0, eIFormat, vDim.x, vDim.y, vDim.z, 0, e_fmt, e_type, null ) );
		
		_vDimension	= vDim;
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		SetBaseLevel( 0 );
		GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}
	
/*
=================================================
	создать uLevels уровней текстуры
=================================================
*/
	bool GLTexture2DArray::Storage(gl_rt_format::type eIFormat, const uvec3 &vDim, uint uLevels, uint8)
	{
		const uint	u_max_levels = GetNumberOfMipmaps( vDim.xy() ) + 1;
		
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_ARRAY_TEXTURE_LAYERS );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );
		CHECK_ERR( uLevels <= u_max_levels );

		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );

		if ( uLevels == 0 )
			uLevels = u_max_levels;

		if ( C_GL_ARB_texture_storage )
		{
			GL_CALL_R( glTextureStorage3D( _uID, _eTarget, eIFormat, uLevels, vDim.x, vDim.y, vDim.z ) );
		}
		else
		{
			gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
			gl_pixel::type			e_type	= gl_pixel::UBYTE;
			GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

			for (uint i = 0; i < uLevels; ++i)
			{
				GL_CALL_R( glTextureImage3D( _uID, _eTarget, i, eIFormat,
											 Max( vDim.x >> i, 1u ), Max( vDim.y >> i, 1u ),
											 vDim.z, 0, e_fmt, e_type, null ) );
			}
		}
		
		_vDimension	= vDim;
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		SetBaseLevel( 0 );
		GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}
	
/*
=================================================
	создать уровень текстуры
=================================================
*/
	bool GLTexture2DArray::CreateLevel(uint uLevel, gl_tex_iformat::type eIFormat)
	{
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension.xy() ) );
		CHECK_ERR( _uID != 0 );

		if ( eIFormat == gl_tex_iformat::_UNKNOWN )
			eIFormat = _eIFormat;
		
		gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
		gl_pixel::type			e_type	= gl_pixel::UBYTE;
		GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

		GL_CALL_R( glTextureImage3D( _uID, _eTarget, uLevel, eIFormat,
									 Max( _vDimension.x >> uLevel, 1u ),
									 Max( _vDimension.y >> uLevel, 1u ),
									 _vDimension.z, 0, e_fmt, e_type, null ) );
		
		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool GLTexture2DArray::SetImage(gl_tex_iformat::type eIFormat, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel)
	{
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_ARRAY_TEXTURE_LAYERS );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );

		bool	b_created = false;

		if ( _uID == 0 )
		{
			CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
			b_created = true;
		}

		GL_CALL_R( glTextureImage3D( _uID, _eTarget, uLevel, eIFormat, vDim.x, vDim.y, vDim.z, 0, eFormat, eType, pData ) );
		

		if ( b_created )
		{
			_vDimension	= uvec3( vDim.xy() << uLevel, vDim.z );
			_eIFormat	= eIFormat;
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
			GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );
		}
		else
		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool GLTexture2DArray::SubImage(const uvec3 &vOffset, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel)
	{
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension ) );
		CHECK_ERR( _uID != 0 );

		GL_CALL_R( glTextureSubImage3D( _uID, _eTarget, uLevel, vOffset.x, vOffset.y, vOffset.z, vDim.x, vDim.y, Max(vDim.z, 1u), eFormat, eType, pData ) );
		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool GLTexture2DArray::SetCompressedImage(gl_tex_iformat::type eIFormat, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel)
	{
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_ARRAY_TEXTURE_LAYERS );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );
		
		bool	b_created = false;

		if ( _uID == 0 )
		{
			CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
			b_created = true;
		}

		GL_CALL_R( glCompressedTextureImage3D( _uID, _eTarget, uLevel, eIFormat, vDim.x, vDim.y, vDim.z, 0, (GLsizei)uDataSize, pData ) );
		
		if ( b_created )
		{
			_vDimension	= uvec3( vDim.xy() << uLevel, vDim.z );
			_eIFormat	= eIFormat;
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
			GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );
		}
		else
		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}
	
/*
=================================================
	
=================================================
*/
	bool GLTexture2DArray::CompressedSubImage(gl_tex_iformat::type eIFormat, const uvec3 &vOffset, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel)
	{
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension ) );
		CHECK_ERR( _uID != 0 );

		if ( eIFormat == gl_tex_iformat::_UNKNOWN and _bCompressed )
			eIFormat = _eIFormat;

		GL_CALL_R( glCompressedTextureSubImage3D( _uID, _eTarget, uLevel, vOffset.x, vOffset.y, vOffset.z,
												  vDim.x, vDim.y, vDim.z, eIFormat, (GLsizei)uDataSize, pData ) );
		return true;
	}

	
	
//-------------------------- GLTexture3D --------------------------//
/*
=================================================
	конструктор
=================================================
*/
	GLTexture3D::GLTexture3D(): GLTexture(gl_texture::TEXTURE_3D)
	{
	}
	
/*
=================================================
	присоединить к кадровому буферу
=================================================
*/
	void GLTexture3D::Attach(GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel, uint uLayer)
	{
		ASSERT( !_bCompressed and "can't render to compressed texture" );
		pFBO->Attach3D( *this, eAttach, uLayer, uLevel );
	}
	
/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTexture3D::Create(gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples)
	{
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_3D_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_3D_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_3D_TEXTURE_SIZE );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim ) )) );

		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
		
		gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
		gl_pixel::type			e_type	= gl_pixel::UBYTE;
		GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

		GL_CALL_R( glTextureImage3D( _uID, _eTarget, 0, eIFormat, vDim.x, vDim.y, vDim.z, 0, e_fmt, e_type, null ) );
		
		_vDimension	= vDim;
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		SetBaseLevel( 0 );
		GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}
	
/*
=================================================
	создает uLevels уровней текстуры
=================================================
*/
	bool GLTexture3D::Storage(gl_rt_format::type eIFormat, const uvec3 &vDim, uint uLevels, uint8)
	{
		const uint	u_max_levels = GetNumberOfMipmaps( vDim ) + 1;
		
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_3D_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_3D_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_3D_TEXTURE_SIZE );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim ) )) );
		CHECK_ERR( uLevels <= u_max_levels );

		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );

		if ( uLevels == 0 )
			uLevels = u_max_levels;

		if ( C_GL_ARB_texture_storage )
		{
			GL_CALL_R( glTextureStorage3D( _uID, _eTarget, eIFormat, uLevels, vDim.x, vDim.y, vDim.z ) );
		}
		else
		{
			gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
			gl_pixel::type			e_type	= gl_pixel::UBYTE;
			GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

			for (uint i = 0; i < uLevels; ++i)
			{
				GL_CALL_R( glTextureImage3D( _uID, _eTarget, i, eIFormat,
											 Max( vDim.x >> i, 1u ), Max( vDim.y >> i, 1u ),
											 Max( vDim.z >> i, 1u ), 0,
											 e_fmt, e_type, null ) );
			}
		}
		
		_vDimension	= vDim;
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		SetBaseLevel( 0 );
		GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}
	
/*
=================================================
	создать уровень текстуры
=================================================
*/
	bool GLTexture3D::CreateLevel(uint uLevel, gl_tex_iformat::type eIFormat)
	{
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension ) );
		CHECK_ERR( _uID != 0 );

		if ( eIFormat == gl_tex_iformat::_UNKNOWN )
			eIFormat = _eIFormat;
		
		gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
		gl_pixel::type			e_type	= gl_pixel::UBYTE;
		GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

		GL_CALL_R( glTextureImage3D( _uID, _eTarget, uLevel, eIFormat,
									 Max( _vDimension.x >> uLevel, 1u ),
									 Max( _vDimension.y >> uLevel, 1u ),
									 Max( _vDimension.z >> uLevel, 1u ), 0,
									 e_fmt, e_type, null ) );
		
		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}
	
/*
=================================================
	добавить изображение в текстуру
=================================================
*/
	bool GLTexture3D::SetImage(gl_tex_iformat::type eIFormat, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel)
	{
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_3D_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_3D_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_3D_TEXTURE_SIZE );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim ) )) );

		bool	b_created = false;

		if ( _uID == 0 )
		{
			CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
			b_created = true;
		}

		GL_CALL_R( glTextureImage3D( _uID, _eTarget, uLevel, eIFormat, vDim.x, vDim.y, vDim.z, 0, eFormat, eType, pData ) );
		

		if ( b_created )
		{
			_vDimension	= vDim << uLevel;
			_eIFormat	= eIFormat;
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
			GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );
		}
		else
		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}
	
/*
=================================================
	добавить участок изображения в текстуру
=================================================
*/
	bool GLTexture3D::SubImage(const uvec3 &vOffset, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel)
	{
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension ) );
		CHECK_ERR( _uID != 0 );

		GL_CALL_R( glTextureSubImage3D( _uID, _eTarget, uLevel, vOffset.x, vOffset.y, vOffset.z, vDim.x, vDim.y, Max(vDim.z, 1u), eFormat, eType, pData ) );
		return true;
	}
	
/*
=================================================
	добавить изображение в текстуру (сжатый формат)
=================================================
*/
	bool GLTexture3D::SetCompressedImage(gl_tex_iformat::type eIFormat, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel)
	{
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_3D_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_3D_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_3D_TEXTURE_SIZE );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim ) )) );
		
		bool	b_created = false;

		if ( _uID == 0 )
		{
			CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
			b_created = true;
		}

		GL_CALL_R( glCompressedTextureImage3D( _uID, _eTarget, uLevel, eIFormat, vDim.x, vDim.y, vDim.z, 0, (GLsizei)uDataSize, pData ) );
		
		if ( b_created )
		{
			_vDimension	= vDim << uLevel;
			_eIFormat	= eIFormat;
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
			GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );
		}
		else
		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}
	
/*
=================================================
	добавить участок изображения в текстуру (сжатый формат)
=================================================
*/
	bool GLTexture3D::CompressedSubImage(gl_tex_iformat::type eIFormat, const uvec3 &vOffset, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel)
	{
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension ) );
		CHECK_ERR( _uID != 0 );

		if ( eIFormat == gl_tex_iformat::_UNKNOWN and _bCompressed )
			eIFormat = _eIFormat;

		GL_CALL_R( glCompressedTextureSubImage3D( _uID, _eTarget, uLevel, vOffset.x, vOffset.y, vOffset.z,
												  vDim.x, vDim.y, vDim.z, eIFormat, (GLsizei)uDataSize, pData ) );
		return true;
	}

	
	
//----------------------- GLTextureCubeArray ----------------------//
/*
=================================================
	конструктор
=================================================
*/
	GLTextureCubeArray::GLTextureCubeArray(): GLTexture(gl_texture::TEXTURE_CUBE_MAP_ARRAY)
	{
		CHECK( C_GL_ARB_texture_cube_map_array );
	}
	
/*
=================================================
	присоединить текстуру к кадровому буферу
=================================================
*/
	void GLTextureCubeArray::Attach(GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel, uint uLayer)
	{
		ASSERT( not _bCompressed and "can't render to compressed texture" );
		pFBO->AttachLayer( *this, eAttach, uLayer, uLevel );
	}
	
/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTextureCubeArray::Create(gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples)
	{
		CHECK_ERR( vDim.z % 6 == 0 );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_ARRAY_TEXTURE_LAYERS );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );

		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
		
		gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
		gl_pixel::type			e_type	= gl_pixel::UBYTE;
		GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

		GL_CALL_R( glTextureImage3D( _uID, _eTarget, 0, eIFormat, vDim.x, vDim.y, vDim.z, 0, e_fmt, e_type, null ) );
		
		_vDimension	= vDim;
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		SetBaseLevel( 0 );
		GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}
	
/*
=================================================
	создает uLevels уровней текстуры
=================================================
*/
	bool GLTextureCubeArray::Storage(gl_rt_format::type eIFormat, const uvec3 &vDim, uint uLevels, uint8)
	{
		const uint	u_max_levels = GetNumberOfMipmaps( vDim.xy() ) + 1;
		
		CHECK_ERR( vDim.z % 6 == 0 );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_ARRAY_TEXTURE_LAYERS );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );
		CHECK_ERR( uLevels <= u_max_levels );

		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );

		if ( uLevels == 0 )
			uLevels = u_max_levels;

		if ( C_GL_ARB_texture_storage )
		{
			GL_CALL_R( glTextureStorage3D( _uID, _eTarget, eIFormat, uLevels, vDim.x, vDim.y, vDim.z ) );
		}
		else
		{
			gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
			gl_pixel::type			e_type	= gl_pixel::UBYTE;
			GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

			for (uint i = 0; i < uLevels; ++i)
			{
				GL_CALL_R( glTextureImage3D( _uID, _eTarget, i, eIFormat,
											 Max( vDim.x >> i, 1u ), Max( vDim.y >> i, 1u ),
											 vDim.z, 0, e_fmt, e_type, null ) );
			}
		}
		
		_vDimension	= vDim;
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		SetBaseLevel( 0 );
		GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}
	
/*
=================================================
	создает пустой уровень текстуры
=================================================
*/
	bool GLTextureCubeArray::CreateLevel(uint uLevel, gl_tex_iformat::type eIFormat)
	{
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension.xy() ) );
		CHECK_ERR( _uID != 0 );

		if ( eIFormat == gl_tex_iformat::_UNKNOWN )
			eIFormat = _eIFormat;
		
		gl_pixel_format::type	e_fmt	= gl_pixel_format::RGBA;
		gl_pixel::type			e_type	= gl_pixel::UBYTE;
		GLTexFormatInfo::GetTexDataFormat( eIFormat, e_fmt, e_type );

		GL_CALL_R( glTextureImage3D( _uID, _eTarget, uLevel, eIFormat,
									 Max( _vDimension.x >> uLevel, 1u ),
									 Max( _vDimension.y >> uLevel, 1u ),
									 _vDimension.z, 0, e_fmt, e_type, null ) );
		
		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}
	
/*
=================================================
	добавить изображение в текстуру
=================================================
*/
	bool GLTextureCubeArray::SetImage(gl_tex_iformat::type eIFormat, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel)
	{
		CHECK_ERR( vDim.z % 6 == 0 );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_ARRAY_TEXTURE_LAYERS );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );

		bool	b_created = false;

		if ( _uID == 0 )
		{
			CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
			b_created = true;
		}

		GL_CALL_R( glTextureImage3D( _uID, _eTarget, uLevel, eIFormat, vDim.x, vDim.y, vDim.z, 0, eFormat, eType, pData ) );
		

		if ( b_created )
		{
			_vDimension	= uvec3( vDim.xy() << uLevel, vDim.z );
			_eIFormat	= eIFormat;
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
			GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );
		}
		else
		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}
	
/*
=================================================
	добавить участок изображения в текстуру
=================================================
*/
	bool GLTextureCubeArray::SubImage(const uvec3 &vOffset, const uvec3 &vDim, gl_pixel_format::type eFormat, gl_pixel::type eType, const void *pData, uint uLevel)
	{
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension ) );
		CHECK_ERR( _uID != 0 );

		GL_CALL_R( glTextureSubImage3D( _uID, _eTarget, uLevel, vOffset.x, vOffset.y, vOffset.z, vDim.x, vDim.y, vDim.z, eFormat, eType, pData ) );
		return true;
	}
	
/*
=================================================
	добавить изображение в текстуру (сжатый формат)
=================================================
*/
	bool GLTextureCubeArray::SetCompressedImage(gl_tex_iformat::type eIFormat, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel)
	{
		CHECK_ERR( vDim.z % 6 == 0 );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_CUBE_MAP_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_ARRAY_TEXTURE_LAYERS );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );
		
		bool	b_created = false;

		if ( _uID == 0 )
		{
			CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
			b_created = true;
		}

		GL_CALL_R( glCompressedTextureImage3D( _uID, _eTarget, uLevel, eIFormat, vDim.x, vDim.y, vDim.z, 0, (GLsizei)uDataSize, pData ) );
		
		if ( b_created )
		{
			_vDimension	= uvec3( vDim.xy() << uLevel, vDim.z );
			_eIFormat	= eIFormat;
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
			GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );
		}
		else
		if ( uLevel < _uMaxLevel ) {
			_uMaxLevel	= uLevel;
			SetBaseLevel( _uMaxLevel );
		}

		return true;
	}
	
/*
=================================================
	добавить участок изображения в текстуру (сжатый формат)
=================================================
*/
	bool GLTextureCubeArray::CompressedSubImage(gl_tex_iformat::type eIFormat, const uvec3 &vOffset, const uvec3 &vDim, const void *pData, usize uDataSize, uint uLevel)
	{
		CHECK_ERR( uLevel <= GetNumberOfMipmaps( _vDimension ) );
		CHECK_ERR( _uID != 0 );

		if ( eIFormat == gl_tex_iformat::_UNKNOWN and _bCompressed )
			eIFormat = _eIFormat;

		GL_CALL_R( glCompressedTextureSubImage3D( _uID, _eTarget, uLevel, vOffset.x, vOffset.y, vOffset.z,
												  vDim.x, vDim.y, vDim.z, eIFormat, (GLsizei)uDataSize, pData ) );
		return true;
	}
	


//------------------------- GLTexture2DMS -------------------------//
/*
=================================================
	конструктор
=================================================
*/
	GLTexture2DMS::GLTexture2DMS(): GLTexture(gl_texture::TEXTURE_2D_MULTISAMPLE)
	{
		//CHECK_ERR( C_GL_ARB_texture_multisample, );
	}

/*
=================================================
	присоединить к кадровому буферу
=================================================
*/
	void GLTexture2DMS::Attach(GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel, uint uLayer)
	{
		pFBO->Attach2D( *this, eAttach, uLevel );
	}

/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTexture2DMS::Create(gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples)
	{
		CHECK_ERR( (vDim.x != 0 and vDim.y != 0) and vDim.z == 0 );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_TEXTURE_SIZE );
		CHECK_ERR( uSamples <= (uint)C_GL_MAX_INTEGER_SAMPLES );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );
		
		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
		
		GL_CALL_R( glTextureImage2DMultisample( _uID, _eTarget, uSamples, eIFormat, vDim.x, vDim.y, GL_TRUE ) );
		
		_vDimension	= uvec3( vDim.xy(), 0 );
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}

/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTexture2DMS::Create(gl_rt_format::type eIFormat, const uvec2 &vDim, uint8 uCoverageSamples, uint8 uColorSamples)
	{
		CHECK_ERR( C_GL_NV_texture_multisample );
		CHECK_ERR( vDim.x != 0 and vDim.y != 0 );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_TEXTURE_SIZE );
		CHECK_ERR( uCoverageSamples <= (uint)C_GL_MAX_INTEGER_SAMPLES and
						uColorSamples <= (uint)C_GL_MAX_INTEGER_SAMPLES );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );
		
		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
		
		GL_CALL_R( glTextureImage2DMultisampleCoverageNV( _uID, _eTarget, uCoverageSamples,
											uColorSamples, eIFormat, vDim.x, vDim.y, GL_TRUE ) );
		
		_vDimension	= uvec3( vDim, 0 );
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}
	
/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTexture2DMS::Storage(gl_rt_format::type eIFormat, const uvec3 &vDim, uint, uint8 uSamples)
	{
		if ( C_GL_ARB_texture_storage_multisample )
		{
			Destroy();
			CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
			GL_CALL_R( glTextureStorage2DMultisample( _uID, _eTarget, uSamples, eIFormat, vDim.x, vDim.y, GL_TRUE ) );
		
			_vDimension	= uvec3( vDim.xy(), 0 );
			_eIFormat	= eIFormat;
			_uMaxLevel	= 0;
			GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );
			return true;
		}
		else
			return Create( eIFormat, uvec3( vDim.xy(), 0 ), uSamples );
	}
	


//----------------------- GLTexture2DMSArray ----------------------//
/*
=================================================
	конструктор
=================================================
*/
	GLTexture2DMSArray::GLTexture2DMSArray(): GLTexture(gl_texture::TEXTURE_2D_MULTISAMPLE_ARRAY)
	{
		//CHECK_ERR( C_GL_ARB_texture_multisample, );
	}

/*
=================================================
	присоединить к кардровому буферу
=================================================
*/
	void GLTexture2DMSArray::Attach(GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel, uint uLayer)
	{
		pFBO->AttachLayer( *this, eAttach, uLayer, uLevel );
	}

/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTexture2DMSArray::Create(gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples)
	{
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_ARRAY_TEXTURE_LAYERS );
		CHECK_ERR( uSamples <= (uint)C_GL_MAX_INTEGER_SAMPLES );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );
		
		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
		
		GL_CALL_R( glTextureImage3DMultisample( _uID, _eTarget, uSamples, eIFormat, vDim.x, vDim.y, vDim.z, GL_TRUE ) );
		
		_vDimension	= vDim;
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}

/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTexture2DMSArray::Create(gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uCoverageSamples, uint8 uColorSamples)
	{
		CHECK_ERR( C_GL_NV_texture_multisample );
		CHECK_ERR(	vDim.x <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.y <= (uint)C_GL_MAX_TEXTURE_SIZE and
						vDim.z <= (uint)C_GL_MAX_ARRAY_TEXTURE_LAYERS );
		CHECK_ERR( uCoverageSamples <= (uint)C_GL_MAX_INTEGER_SAMPLES and
						uColorSamples <= (uint)C_GL_MAX_INTEGER_SAMPLES );
		//CHECK_ERR( C_GL_ARB_texture_non_power_of_two or
		//			 (!C_GL_ARB_texture_non_power_of_two and All( IsPowerOfTwo( vDim.xy() ) )) );
		
		Destroy();
		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
		
		GL_CALL_R( glTextureImage3DMultisampleCoverageNV( _uID, _eTarget, uCoverageSamples,
									uColorSamples, eIFormat, vDim.x, vDim.y, vDim.z, GL_TRUE ) );
		
		_vDimension	= vDim;
		_eIFormat	= eIFormat;
		_uMaxLevel	= 0;
		GLTexFormatInfo::GetSupportedFlags( _eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}
	
/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTexture2DMSArray::Storage(gl_rt_format::type eIFormat, const uvec3 &vDim, uint, uint8 uSamples)
	{
		if ( C_GL_ARB_texture_storage_multisample )
		{
			Destroy();
			CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
			GL_CALL_R( glTextureStorage3DMultisample( _uID, _eTarget, uSamples, eIFormat,
													  vDim.x, vDim.y, vDim.z, GL_TRUE ) );
		
			_vDimension	= vDim;
			_eIFormat	= eIFormat;
			_uMaxLevel	= 0;
			GLTexFormatInfo::GetSupportedFlags( eIFormat, _bCompressed, _bImageSupported, _bRenderable );
			return true;
		}
		else
			return Create( eIFormat, vDim, uSamples );
	}
	


//------------------------- GLTextureView -------------------------//
/*
=================================================
	конструктор
=================================================
*/
	GLTextureView::GLTextureView(): GLTexture(gl_texture::TEXTURE_VIEW)
	{
	}
	
/*
=================================================
	присоединить текстуру к кадровому буферу
=================================================
*/
	void GLTextureView::Attach(GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel, uint uLayer)
	{
		switch ( _eTarget )
		{
			case gl_texture::TEXTURE_2D :
			case gl_texture::TEXTURE_2D_MULTISAMPLE :
				pFBO->Attach2D( (const GLTexture2D &)*this, eAttach, uLevel );
			
			case gl_texture::TEXTURE_3D :
			case gl_texture::TEXTURE_2D_ARRAY:
			case gl_texture::TEXTURE_CUBE_MAP_ARRAY :
			case gl_texture::TEXTURE_2D_MULTISAMPLE_ARRAY :
				pFBO->AttachLayer( (const GLTexture2DArray &)*this, eAttach, uLayer, uLevel );
			
			case gl_texture::TEXTURE_CUBE_MAP :
				pFBO->AttachFace( (const GLTextureCube &)*this, eAttach, gl_cube_face::_FIRST + uLayer, uLevel );
		};
	}

/*
=================================================
	не поддерживается
=================================================
*/
	bool GLTextureView::Create(gl_rt_format::type eIFormat, const uvec3 &vDim, uint8 uSamples)
	{
		RETURN_ERR( "not supported for TextureView" );
	}
	
/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTextureView::Create(gl_texture::type eTarget, const GLTexture *pTexture, gl_tex_iformat::type eIFormat,
								uint uMinLevel, uint uNumLevels, uint uMinLayer, uint uNumLayers)
	{
		CHECK_ERR( pTexture != null );
		CHECK_ERR( s_CheckTargetSupport( pTexture->Target(), eTarget ) );

		Destroy();

		CHECK_ERR( GLOM()->GenTextures( 1, &_uID ) );
		GL_CALL_R( glTextureView( _uID, eTarget, pTexture->Id(), eIFormat,
									uMinLevel, uNumLevels, uMinLayer, uNumLayers ) );
		_eIFormat	= eIFormat;
		_uMaxLevel	= uMinLevel;
		_vDimension	= pTexture->LevelDimension( uMinLevel );
		GLTexFormatInfo::GetSupportedFlags( _eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		return true;
	}
	
/*
=================================================
	проверяет совместимость целей привязки
	исходной текстуры и создаваемой view текстуры
=================================================
*/
	bool GLTextureView::s_CheckTargetSupport(gl_texture::type eSrcTarget, gl_texture::type eViewTarget)
	{
		switch ( eSrcTarget )
		{
			case gl_texture::TEXTURE_1D :
			case gl_texture::TEXTURE_1D_ARRAY :
				return	eViewTarget == gl_texture::TEXTURE_1D or
						eViewTarget == gl_texture::TEXTURE_1D_ARRAY;

			case gl_texture::TEXTURE_2D :
				return	eViewTarget == gl_texture::TEXTURE_2D or
						eViewTarget == gl_texture::TEXTURE_2D_ARRAY;

			case gl_texture::TEXTURE_3D :
				return	eViewTarget == gl_texture::TEXTURE_3D;

			case gl_texture::TEXTURE_RECTANGLE :
				return eViewTarget == gl_texture::TEXTURE_RECTANGLE;

			case gl_texture::TEXTURE_CUBE_MAP :
			case gl_texture::TEXTURE_2D_ARRAY :
			case gl_texture::TEXTURE_CUBE_MAP_ARRAY :
				return	eViewTarget == gl_texture::TEXTURE_2D or
						eViewTarget == gl_texture::TEXTURE_CUBE_MAP or
						eViewTarget == gl_texture::TEXTURE_2D_ARRAY or
						eViewTarget == gl_texture::TEXTURE_CUBE_MAP_ARRAY;

			case gl_texture::TEXTURE_2D_MULTISAMPLE :
			case gl_texture::TEXTURE_2D_MULTISAMPLE_ARRAY :
				return	eViewTarget == gl_texture::TEXTURE_2D_MULTISAMPLE or
						eViewTarget == gl_texture::TEXTURE_2D_MULTISAMPLE_ARRAY;
		};
		WARNING( "unknown or unsupported texture target" );
		return false;
	}



//------------------------ GLTextureBuffer ------------------------//
/*
=================================================
	конструктор
=================================================
*/
	GLTextureBuffer::GLTextureBuffer(): GLTexture(gl_texture::TEXTURE_BUFFER)
	{
		_uMaxLevel	= 0;
	}

/*
=================================================
	не поддерживаются
=================================================
*/
	void GLTextureBuffer::Attach(GLFrameBuffer *pFBO, gl_fbo_attach::type eAttach, uint uLevel, uint uLayer) { WARNING("can't attach TBO to FBO"); return; }
	bool GLTextureBuffer::Create(gl_rt_format::type eFormat, const uvec3 &vDim, uint8 uSamples) { return false; }

/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTextureBuffer::Create(gl_tbo_iformat::type eIFormat)
	{
		Destroy();
		CHECK_ERR( GLBuffer::Create( gl_buffer::TEXTURE ) );
		CHECK_ERR( GLOM()->GenTextures( 1, & (GLTexture::_uID) ) );
		
		_eIFormat	= eIFormat;
		GLTexFormatInfo::GetSupportedFlags( _eIFormat, _bCompressed, _bImageSupported, _bRenderable );

		DEBUG_ONLY(
			uint	u_channels = 0;
			if ( GLTexFormatInfo::GetChannels( _eIFormat, u_channels ) ) {
				ASSERT( u_channels != 3 and "RGB format may be unsupported for TextureBuffer\n"
						"to check support write in shader: \"#extension GL_ARB_texture_buffer_object_rgb32 : enable\"" );
			}
		)

		return true;
	}

/*
=================================================
	удалить текстуру
=================================================
*/
	void GLTextureBuffer::Destroy()
	{
		GLTexture::Destroy();
		GLBuffer::Destroy();
	}



//----------------------- GLTextureDynBuffer ----------------------//
/*
=================================================
	конструктор
=================================================
*/
	GLTextureDynBuffer::GLTextureDynBuffer(): _aBuffer(), _uElemSize(-1)
	{
	}
		
/*
=================================================
	создать текстуру
=================================================
*/
	bool GLTextureDynBuffer::Create(gl_tbo_iformat::type eIFormat, uint16 uElemSize, usize uReserve)
	{
		CHECK_ERR( uElemSize != 0 );

		CHECK_ERR( GLTextureBuffer::Create( eIFormat ) );
		CHECK_ALLOC( _aBuffer.Reserve( uReserve ) );
		_uElemSize	= uElemSize;
		return true;
	}

/*
=================================================
	удалить текстуру
=================================================
*/
	void GLTextureDynBuffer::Destroy()
	{
		GLTextureBuffer::Destroy();
		_aBuffer.Clear();
		_uElemSize = -1;
	}


	
//------------------------ GLTexFormatInfo ------------------------//

	struct GLTexIFormat
	{
		gl_tex_iformat::type	ifmt;
		gl_tex_component::type	type;
		uint16					size;	// bit per pixel
		uint8					channels;
		bool					compressed		: 1,
								image_binding	: 1,
								renderable		: 1;
		gl_pixel::type			pixtype;
		gl_pixel_format::type	pixfmt;
	};

	namespace gl_texc { using namespace gl_tex_component; }
	namespace gl_pixfmt { using namespace gl_pixel_format; }


	static const GLTexIFormat	s_aTexIFormats[] = {
		// depth & stencil
		{ gl_tex_iformat::DEPTH16,				gl_texc::NONE,		16,		1,	false,	false,	true,	gl_pixel::UBYTE,				gl_pixfmt::DEPTH },
		{ gl_tex_iformat::DEPTH24,				gl_texc::NONE,		24,		1,	false,	false,	true,	gl_pixel::UBYTE,				gl_pixfmt::DEPTH },
		{ gl_tex_iformat::DEPTH32,				gl_texc::NONE,		32,		1,	false,	false,	true,	gl_pixel::UBYTE,				gl_pixfmt::DEPTH },
		{ gl_tex_iformat::DEPTH32F,				gl_texc::FLOAT,		32,		1,	false,	false,	true,	gl_pixel::FLOAT,				gl_pixfmt::DEPTH },
		{ gl_tex_iformat::DEPTH24_STENCIL8,		gl_texc::NONE,		24+8,	2,	false,	false,	true,	gl_pixel::UINT_24_8,			gl_pixfmt::DEPTH_STENCIL },
		{ gl_tex_iformat::DEPTH32F_STENCIL8,	gl_texc::NONE,		32+8,	2,	false,	false,	true,	gl_pixel::FLOAT32_UINT_24_8,	gl_pixfmt::DEPTH_STENCIL },
		// unsigned normalized
		{ gl_tex_iformat::R8,					gl_texc::UNORM,		8,		1,	false,	true,	true,	gl_pixel::UBYTE,				gl_pixfmt::RED	},
		{ gl_tex_iformat::R16,					gl_texc::UNORM,		16,		1,	false,	true,	true,	gl_pixel::USHORT,				gl_pixfmt::RED	},
		{ gl_tex_iformat::RG8,					gl_texc::UNORM,		8*2,	2,	false,	true,	true,	gl_pixel::UBYTE,				gl_pixfmt::RG	},
		{ gl_tex_iformat::RG16,					gl_texc::UNORM,		16*2,	2,	false,	true,	true,	gl_pixel::USHORT,				gl_pixfmt::RG	},
		{ gl_tex_iformat::R3_G3_B2,				gl_texc::UNORM,		3+3+2,	3,	false,	false,	true,	gl_pixel::UBYTE_3_3_2,			gl_pixfmt::RGB	},
		{ gl_tex_iformat::RGB4,					gl_texc::UNORM,		4*3,	3,	false,	false,	true,	gl_pixel::USHORT_4_4_4_4,		gl_pixfmt::RGB	},
		{ gl_tex_iformat::RGB5,					gl_texc::UNORM,		5*3,	3,	false,	false,	true,	gl_pixel::USHORT_5_6_5,			gl_pixfmt::RGB	},
		{ gl_tex_iformat::RGB8,					gl_texc::UNORM,		8*3,	3,	false,	false,	true,	gl_pixel::UBYTE,				gl_pixfmt::RGB	},
		{ gl_tex_iformat::RGB10,				gl_texc::UNORM,		10*3,	3,	false,	false,	true,	gl_pixel::UBYTE,				gl_pixfmt::RGB	},
		{ gl_tex_iformat::RGB12,				gl_texc::UNORM,		12*3,	3,	false,	false,	true,	gl_pixel::UBYTE,				gl_pixfmt::RGB	},
		{ gl_tex_iformat::RGB16,				gl_texc::UNORM,		16*3,	3,	false,	false,	true,	gl_pixel::USHORT,				gl_pixfmt::RGB	},
		{ gl_tex_iformat::RGBA2,				gl_texc::UNORM,		2*4,	4,	false,	false,	true,	gl_pixel::UBYTE,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::RGBA4,				gl_texc::UNORM,		4*4,	4,	false,	false,	true,	gl_pixel::USHORT_4_4_4_4,		gl_pixfmt::RGBA	},
		{ gl_tex_iformat::RGB5_A1,				gl_texc::UNORM,		3*5+1,	4,	false,	false,	true,	gl_pixel::USHORT_5_5_5_1,		gl_pixfmt::RGBA	},
		{ gl_tex_iformat::RGBA8,				gl_texc::UNORM,		8*4,	4,	false,	true,	true,	gl_pixel::UBYTE,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::RGB10_A2,				gl_texc::UNORM,		10*3+2,	4,	false,	true,	true,	gl_pixel::UINT_10_10_10_2,		gl_pixfmt::RGBA	},
		{ gl_tex_iformat::RGBA12,				gl_texc::UNORM,		12*4,	4,	false,	false,	true,	gl_pixel::USHORT,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::RGBA16,				gl_texc::UNORM,		16*4,	4,	false,	true,	true,	gl_pixel::USHORT,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::SRGB8,				gl_texc::UNORM,		8*3,	3,	false,	false,	true,	gl_pixel::UBYTE,				gl_pixfmt::RGB	},
		{ gl_tex_iformat::SRGBA8,				gl_texc::UNORM,		8*4,	4,	false,	false,	true,	gl_pixel::UBYTE,				gl_pixfmt::RGBA	},
		// signed normalized
		{ gl_tex_iformat::R8_SNORM,				gl_texc::SNORM,		8,		1,	false,	true,	false,	gl_pixel::BYTE,					gl_pixfmt::RED	},
		{ gl_tex_iformat::R16_SNORM,			gl_texc::SNORM,		16,		1,	false,	true,	false,	gl_pixel::SHORT,				gl_pixfmt::RED	},
		{ gl_tex_iformat::RG8_SNORM,			gl_texc::SNORM,		8*2,	2,	false,	true,	false,	gl_pixel::BYTE,					gl_pixfmt::RG	},
		{ gl_tex_iformat::RG16_SNORM,			gl_texc::SNORM,		16*2,	2,	false,	true,	false,	gl_pixel::SHORT,				gl_pixfmt::RG	},
		{ gl_tex_iformat::RGB8_SNORM,			gl_texc::SNORM,		8*3,	3,	false,	false,	false,	gl_pixel::BYTE,					gl_pixfmt::RGB	},
		{ gl_tex_iformat::RGB16_SNORM,			gl_texc::SNORM,		16*3,	3,	false,	false,	false,	gl_pixel::SHORT,				gl_pixfmt::RGB	},
		{ gl_tex_iformat::RGBA8_SNORM,			gl_texc::SNORM,		8*4,	4,	false,	true,	false,	gl_pixel::BYTE,					gl_pixfmt::RGBA	},
		{ gl_tex_iformat::RGBA16_SNORM,			gl_texc::SNORM,		16*4,	4,	false,	true,	false,	gl_pixel::SHORT,				gl_pixfmt::RGBA	},
		// float
		{ gl_tex_iformat::RGBA32F,				gl_texc::FLOAT,		32*4,	4,	false,	true,	true,	gl_pixel::FLOAT,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::RGBA16F,				gl_texc::FLOAT,		16*4,	4,	false,	true,	true,	gl_pixel::HALF,					gl_pixfmt::RGBA	},
		{ gl_tex_iformat::RGB32F,				gl_texc::FLOAT,		32*3,	3,	false,	false,	true,	gl_pixel::FLOAT,				gl_pixfmt::RGB	},
		{ gl_tex_iformat::RGB16F,				gl_texc::FLOAT,		16*3,	3,	false,	false,	true,	gl_pixel::HALF,					gl_pixfmt::RGB	},
		{ gl_tex_iformat::RG32F,				gl_texc::FLOAT,		32*2,	2,	false,	true,	true,	gl_pixel::FLOAT,				gl_pixfmt::RG	},
		{ gl_tex_iformat::RG16F,				gl_texc::FLOAT,		16*2,	2,	false,	true,	true,	gl_pixel::HALF,					gl_pixfmt::RG	},
		{ gl_tex_iformat::R32F,					gl_texc::FLOAT,		32,		1,	false,	true,	true,	gl_pixel::FLOAT,				gl_pixfmt::R	},
		{ gl_tex_iformat::R16F,					gl_texc::FLOAT,		32,		1,	false,	true,	true,	gl_pixel::HALF,					gl_pixfmt::R	},
		{ gl_tex_iformat::R11F_G11F_B10F,		gl_texc::FLOAT,		32,		3,	false,	true,	true,	gl_pixel::UINT_10F_11F_11F_REV,	gl_pixfmt::RGB	},
		{ gl_tex_iformat::RGB9_E5,				gl_texc::FLOAT,		32,		3,	false,	false,	true,	gl_pixel::UINT_5_9_9_9_REV,		gl_pixfmt::RGB	},
		// integer
		{ gl_tex_iformat::RGBA32I,				gl_texc::INT,		32*4,	4,	false,	true,	true,	gl_pixel::INT,					gl_pixfmt::RGBA_INTEGER	},
		{ gl_tex_iformat::RGBA16I,				gl_texc::INT,		16*4,	4,	false,	true,	true,	gl_pixel::SHORT,				gl_pixfmt::RGBA_INTEGER	},
		{ gl_tex_iformat::RGBA8I,				gl_texc::INT,		8*4,	4,	false,	true,	true,	gl_pixel::BYTE,					gl_pixfmt::RGBA_INTEGER	},
		{ gl_tex_iformat::RGB32I,				gl_texc::INT,		32*3,	3,	false,	false,	true,	gl_pixel::INT,					gl_pixfmt::RGB_INTEGER	},
		{ gl_tex_iformat::RGB16I,				gl_texc::INT,		16*3,	3,	false,	false,	true,	gl_pixel::SHORT,				gl_pixfmt::RGB_INTEGER	},
		{ gl_tex_iformat::RGB8I,				gl_texc::INT,		8*3,	3,	false,	false,	true,	gl_pixel::BYTE,					gl_pixfmt::RGB_INTEGER	},
		{ gl_tex_iformat::RG32I,				gl_texc::INT,		32*2,	2,	false,	true,	true,	gl_pixel::INT,					gl_pixfmt::RG_INTEGER	},
		{ gl_tex_iformat::RG16I,				gl_texc::INT,		16*2,	2,	false,	true,	true,	gl_pixel::SHORT,				gl_pixfmt::RG_INTEGER	},
		{ gl_tex_iformat::RG8I,					gl_texc::INT,		8*2,	2,	false,	true,	true,	gl_pixel::BYTE,					gl_pixfmt::RG_INTEGER	},
		{ gl_tex_iformat::R32I,					gl_texc::INT,		32,		1,	false,	true,	true,	gl_pixel::INT,					gl_pixfmt::RED_INTEGER	},
		{ gl_tex_iformat::R16I,					gl_texc::INT,		16,		1,	false,	true,	true,	gl_pixel::SHORT,				gl_pixfmt::RED_INTEGER	},
		{ gl_tex_iformat::R8I,					gl_texc::INT,		8,		1,	false,	true,	true,	gl_pixel::BYTE,					gl_pixfmt::RED_INTEGER	},
		// unsigned integer
		{ gl_tex_iformat::RGB10_A2UI,			gl_texc::UINT,		10*3+2,	4,	false,	true,	true,	gl_pixel::UINT_10_10_10_2,		gl_pixfmt::RGBA_INTEGER	},
		{ gl_tex_iformat::RGBA32UI,				gl_texc::UINT,		32*4,	4,	false,	true,	true,	gl_pixel::UINT,					gl_pixfmt::RGBA_INTEGER	},
		{ gl_tex_iformat::RGBA16UI,				gl_texc::UINT,		16*4,	4,	false,	true,	true,	gl_pixel::USHORT,				gl_pixfmt::RGBA_INTEGER	},
		{ gl_tex_iformat::RGBA8UI,				gl_texc::UINT,		8*4,	4,	false,	true,	true,	gl_pixel::UBYTE,				gl_pixfmt::RGBA_INTEGER	},
		{ gl_tex_iformat::RGB32UI,				gl_texc::UINT,		32*3,	3,	false,	false,	true,	gl_pixel::UINT,					gl_pixfmt::RGB_INTEGER	},
		{ gl_tex_iformat::RGB16UI,				gl_texc::UINT,		16*3,	3,	false,	false,	true,	gl_pixel::USHORT,				gl_pixfmt::RGB_INTEGER	},
		{ gl_tex_iformat::RGB8UI,				gl_texc::UINT,		8*3,	3,	false,	false,	true,	gl_pixel::UBYTE,				gl_pixfmt::RGB_INTEGER	},
		{ gl_tex_iformat::RG32UI,				gl_texc::UINT,		32*2,	2,	false,	true,	true,	gl_pixel::UINT,					gl_pixfmt::RG_INTEGER	},
		{ gl_tex_iformat::RG16UI,				gl_texc::UINT,		16*2,	2,	false,	true,	true,	gl_pixel::USHORT,				gl_pixfmt::RG_INTEGER	},
		{ gl_tex_iformat::RG8UI,				gl_texc::UINT,		8*2,	2,	false,	true,	true,	gl_pixel::UBYTE,				gl_pixfmt::RG_INTEGER	},
		{ gl_tex_iformat::R32UI,				gl_texc::UINT,		32,		1,	false,	true,	true,	gl_pixel::UINT,					gl_pixfmt::RED_INTEGER	},
		{ gl_tex_iformat::R16UI,				gl_texc::UINT,		16,		1,	false,	true,	true,	gl_pixel::USHORT,				gl_pixfmt::RED_INTEGER	},
		{ gl_tex_iformat::R8UI,					gl_texc::UINT,		8,		1,	false,	true,	true,	gl_pixel::UBYTE,				gl_pixfmt::RED_INTEGER	},
		// for render buffer only
		{ gl_rt_format::STENCIL1,				gl_texc::NONE,		1,		1,	false,	false,	true,	gl_pixel::UBYTE,				gl_pixfmt::STENCIL	},
		{ gl_rt_format::STENCIL4,				gl_texc::NONE,		4,		1,	false,	false,	true,	gl_pixel::UBYTE,				gl_pixfmt::STENCIL	},
		{ gl_rt_format::STENCIL8,				gl_texc::NONE,		8,		1,	false,	false,	true,	gl_pixel::UBYTE,				gl_pixfmt::STENCIL	},
		{ gl_rt_format::STENCIL16,				gl_texc::NONE,		16,		1,	false,	false,	true,	gl_pixel::USHORT,				gl_pixfmt::STENCIL	},
		// compressed formats
		{ gl_tex_iformat::COMPRESSED_RED,		gl_texc::UNORM,		0,		1,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RED	},
		{ gl_tex_iformat::COMPRESSED_RG,		gl_texc::UNORM,		0,		2,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RG	},
		{ gl_tex_iformat::COMPRESSED_RGB,		gl_texc::UNORM,		0,		3,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGB	},
		{ gl_tex_iformat::COMPRESSED_RGBA,		gl_texc::UNORM,		0,		4,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::COMPRESSED_SRGB,		gl_texc::UNORM,		0,		3,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGB	},
		{ gl_tex_iformat::COMPRESSED_SRGBA,		gl_texc::UNORM,		0,		4,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::DXT1_RGB8,			gl_texc::UNORM,		4,		3,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGB	},
		{ gl_tex_iformat::DXT1_RGB8_A1,			gl_texc::UNORM,		4,		4,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::DXT3_RGBA8,			gl_texc::UNORM,		8,		4,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::DXT5_RGBA8,			gl_texc::UNORM,		8,		4,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::RGTC1_RED8,			gl_texc::UNORM,		2,		1,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RED	},
		{ gl_tex_iformat::RGTC1_RED8_SNORM,		gl_texc::SNORM,		2,		1,	true,	false,	false,	gl_pixel::BYTE,					gl_pixfmt::RED	},
		{ gl_tex_iformat::RGTC2_RG8,			gl_texc::UNORM,		4,		2,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RG	},
		{ gl_tex_iformat::RGTC2_RG8_SNORM,		gl_texc::SNORM,		4,		2,	true,	false,	false,	gl_pixel::BYTE,					gl_pixfmt::RG	},
		{ gl_tex_iformat::BPTC_RGBA8,			gl_texc::UNORM,		8,		4,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::BPTC_SRGBA8,			gl_texc::UNORM,		8,		4,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::BPTC_RGB16F_SIGNED,	gl_texc::FLOAT,		8,		3,	true,	false,	false,	gl_pixel::HALF,					gl_pixfmt::RGB	},
		{ gl_tex_iformat::BPTC_RGB16F_UNSIGNED,	gl_texc::FLOAT,		8,		3,	true,	false,	false,	gl_pixel::HALF,					gl_pixfmt::RGB	},
		{ gl_tex_iformat::ETC2_RGB8,			gl_texc::UNORM,		4,		3,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGB	},
		{ gl_tex_iformat::ECT2_SRGB8,			gl_texc::UNORM,		4,		3,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGB	},
		{ gl_tex_iformat::ETC2_RGB8_A1,			gl_texc::UNORM,		0,		4,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::ETC2_SRGB8_A1,		gl_texc::UNORM,		0,		4,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::ETC2_RGBA8,			gl_texc::UNORM,		0,		3,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGB	},
		{ gl_tex_iformat::ETC2_SRGB8_A8,		gl_texc::UNORM,		0,		4,	true,	false,	false,	gl_pixel::UBYTE,				gl_pixfmt::RGBA	},
		{ gl_tex_iformat::EAC_R11,				gl_texc::UNORM,		0,		1,	true,	false,	false,	gl_pixel::USHORT,				gl_pixfmt::RED	},
		{ gl_tex_iformat::EAC_R11_SIGNED,		gl_texc::SNORM,		0,		1,	true,	false,	false,	gl_pixel::SHORT,				gl_pixfmt::RED	},
		{ gl_tex_iformat::EAC_RG11,				gl_texc::UNORM,		0,		2,	true,	false,	false,	gl_pixel::USHORT,				gl_pixfmt::RG	},
		{ gl_tex_iformat::EAC_RG11_SIGNED,		gl_texc::SNORM,		0,		2,	true,	false,	false,	gl_pixel::SHORT,				gl_pixfmt::RG	}
	};


	struct GLTexFormat
	{
		gl_pixel_format::type	eFormat;
		uint8					uChannels;
		bool					bInteger	: 1,
								bInversed	: 1;	// BGRA formats
	};

	static const GLTexFormat	s_aTexFormats[] =
	{
		{ gl_pixel_format::RED,				1,	false,	false },
		{ gl_pixel_format::RED_INTEGER,		1,	true,	false },
		{ gl_pixel_format::RG,				2,	false,	false },
		{ gl_pixel_format::RG_INTEGER,		2,	true,	false },
		{ gl_pixel_format::RGB,				3,	false,	false },
		{ gl_pixel_format::RGB_INTEGER,		3,	true,	false },
		{ gl_pixel_format::BGR,				3,	false,	true  },
		{ gl_pixel_format::BGR_INTEGER,		3,	true,	true  },
		{ gl_pixel_format::RGBA,			4,	false,	false },
		{ gl_pixel_format::RGBA_INTEGER,	4,	true,	false },
		{ gl_pixel_format::BGRA,			4,	false,	true  },
		{ gl_pixel_format::BGRA_INTEGER,	4,	true,	true  },
		{ gl_pixel_format::DEPTH,			1,	false,	false },
		{ gl_pixel_format::DEPTH_STENCIL,	2,	false,	false },
		{ gl_pixel_format::STENCIL,			1,	false,	false }
	};


	struct GLTexData
	{
		gl_pixel::type		eType;
		uint16				uSize;
		uint8				uChannels;
		bool				bInteger	: 1;
	};

	static const GLTexData		s_aTexDataType[] =
	{
		{ gl_pixel::UBYTE,					8,		0,	true  },
		{ gl_pixel::BYTE,					8,		0,	true  },
		{ gl_pixel::USHORT,					16,		0,	true  },
		{ gl_pixel::SHORT,					16,		0,	true  },
		{ gl_pixel::UINT,					32,		0,	true  },
		{ gl_pixel::INT,					32,		0,	true  },
		{ gl_pixel::HALF,					16,		0,	false },
		//{ gl_pixel::FIXED,				32,		0,	false },
		{ gl_pixel::FLOAT,					32,		0,	false },
		//{ gl_pixel::DOUBLE,				64,		0,	false },
		{ gl_pixel::UBYTE_3_3_2,			8,		3,	false },
		{ gl_pixel::UBYTE_2_3_3_REV,		8,		3,	false },
		{ gl_pixel::USHORT_5_6_5,			16,		3,	false },
		{ gl_pixel::USHORT_5_6_5_REV,		16,		3,	false },
		{ gl_pixel::USHORT_4_4_4_4,			16,		4,	false },
		{ gl_pixel::USHORT_4_4_4_4_REV,		16,		4,	false },
		{ gl_pixel::USHORT_5_5_5_1,			16,		4,	false },
		{ gl_pixel::USHORT_1_5_5_5_REV,		16,		4,	false },
		{ gl_pixel::UINT_8_8_8_8,			32,		4,	false },
		{ gl_pixel::UINT_8_8_8_8_REV,		32,		4,	false },
		{ gl_pixel::UINT_10_10_10_2,		32,		4,	true  },
		{ gl_pixel::UINT_2_10_10_10_REV,	32,		4,	true  },
		{ gl_pixel::UINT_10F_11F_11F_REV,	32,		3,	false },
		{ gl_pixel::UINT_5_9_9_9_REV,		32,		4,	false },
		{ gl_pixel::UINT_24_8,				32,		2,	false },
		{ gl_pixel::FLOAT32_UINT_24_8,		32,		2,	false }
	};

/*
=================================================
	является ли формат сжатым
=================================================
*/
	bool GLTexFormatInfo::IsCompressed(gl_tex_iformat::type eIFormat)
	{
		bool	b_res = false;
		return GetParams( eIFormat, null, null, null, &b_res, null, null ) and b_res;
	}

/*
=================================================
	поддерживается ли биндинг уровня текстуры
=================================================
*/
	bool GLTexFormatInfo::IsImageSupported(gl_tex_iformat::type eIFormat)
	{
		bool	b_res = false;
		return GetParams( eIFormat, null, null, null, null, &b_res, null ) and b_res;
	}
	
/*
=================================================
	поддерживается ли рендеринг в текстуру
=================================================
*/
	bool GLTexFormatInfo::IsRenderableFormat(gl_tex_iformat::type eIFormat)
	{
		bool	b_res = false;
		return GetParams( eIFormat, null, null, null, null, null, &b_res ) and b_res;
	}

/*
=================================================
	возвращает подходящий формат данны текстуры
	в зависимости от внутреннего формата
=================================================
*/
	bool GLTexFormatInfo::GetTexDataFormat(gl_tex_iformat::type eIFormat, gl_pixel_format::type &eFormat, gl_pixel::type &eType)
	{
		for (usize i = 0; i < CountOf(s_aTexIFormats); ++i)
		{
			if ( eIFormat == s_aTexIFormats[i].ifmt )
			{
				eFormat = s_aTexIFormats[i].pixfmt;
				eType	= s_aTexIFormats[i].pixtype;
				return true;
			}
		}
		return false;

		/*uint					u_channels,
								u_bpp;
		gl_tex_component::type	e_type;
		bool					b_compressed,
								b_img_supported;

		if ( !GetParams( eIFormat, &u_channels, &e_type, &u_bpp, &b_compressed, &b_img_supported ) )
			return false;

		if ( b_compressed ) {
			WARNING( "Not supported for compressed formats!" );
			return false;
		}

		switch ( u_channels )
		{
			case 1 :
				if ( e_type == gl_tex_component::INT or e_type == gl_tex_component::UINT )
					eFormat = gl_pixel_format::RED_INTEGER;
				else
					eFormat = gl_pixel_format::RED;
				break;

			case 2 :
				if ( e_type == gl_tex_component::INT or e_type == gl_tex_component::UINT )
					eFormat = gl_pixel_format::RG_INTEGER;
				else
					eFormat = gl_pixel_format::RG;
				break;

			case 3 :
				if ( e_type == gl_tex_component::INT or e_type == gl_tex_component::UINT )
					eFormat = gl_pixel_format::RG_INTEGER;
				else
					eFormat = gl_pixel_format::RG;
				break;

			case 4 :
				if ( e_type == gl_tex_component::INT or e_type == gl_tex_component::UINT )
					eFormat = gl_pixel_format::RG_INTEGER;
				else
					eFormat = gl_pixel_format::RG;
				break;

			default :
				WARNING( "Not supported channels number." );
				return false;
		}

		if ( e_type == gl_tex_component::FLOAT or
			 e_type == gl_tex_component::INT or
			 e_type == gl_tex_component::UINT )
		{
			eType = (gl_pixel::type) e_type;
		}
		else
		if ( e_type == gl_tex_component::SNORM )
		{
			eType = gl_pixel::INT;
		}
		else
		if ( e_type == gl_tex_component::UNORM )
		{
			eType = gl_pixel::UINT;
		}
		else
			eType = gl_pixel::FLOAT;

		return true;*/
	}
	
/*
=================================================
	возвращает информацию о поддержке
	бинда уровня текстуры и используется ли сжатие
=================================================
*/
	bool GLTexFormatInfo::GetSupportedFlags(gl_tex_iformat::type eIFormat, bool &bCompressed, bool &bImageSupported, bool &bIsRenderable)
	{
		return GetParams( eIFormat, null, null, null, &bCompressed, &bImageSupported, &bIsRenderable );
	}
	
/*
=================================================
	возвращает информаци о текстурном формате
=================================================
*/
	bool GLTexFormatInfo::GetParams(gl_tex_iformat::type eIFormat, uint *pChannels, gl_tex_component::type *pType,
									uint *pBitPP, bool *pCompressed, bool *pImageSupported, bool *pRenderable)
	{
		for (usize i = 0; i < CountOf( s_aTexIFormats ); ++i)
		{
			if ( eIFormat == s_aTexIFormats[i].ifmt )
			{
				pChannels != null		?	*pChannels = s_aTexIFormats[i].channels : 0;
				pType != null			?	*pType = s_aTexIFormats[i].type : 0;
				pBitPP != null			?	*pBitPP = s_aTexIFormats[i].size : 0;
				pCompressed != null		?	*pCompressed = s_aTexIFormats[i].compressed : 0;
				pImageSupported != null	?	*pImageSupported = s_aTexIFormats[i].image_binding : 0;
				pRenderable != null		?	*pRenderable = s_aTexIFormats[i].renderable : 0;
				return true;
			}
		}

		return false;
	}
	
/*
=================================================
	возвращает количество каналов в текстуре
=================================================
*/
	bool GLTexFormatInfo::GetChannels(gl_tex_iformat::type eIFormat, uint &uChannels)
	{
		return GetParams( eIFormat, &uChannels, null, null, null, null, null );
	}

/*
=================================================
	возвращает формат данных текстуры
=================================================
*/
	bool GLTexFormatInfo::GetComponentType(gl_tex_iformat::type eIFormat, gl_tex_component::type &eType)
	{
		return GetParams( eIFormat, null, &eType, null, null, null, null );
	}

/*
=================================================
	возвращает размер пиксела в битах
	для внутреннего формата текстуры
=================================================
*/
	bool GLTexFormatInfo::GetBitPerPixel(gl_tex_iformat::type eIFormat, uint &uBPP)
	{
		return GetParams( eIFormat, null, null, &uBPP, null, null, null );
	}
	
/*
=================================================
	возвращает размер пиксела в битах
	для формата данных текстуры
=================================================
*/
	bool GLTexFormatInfo::GetBitPerPixel(gl_pixel_format::type eFormat, gl_pixel::type eType, uint &uBPP)
	{
		uint	u_fmt_channels	= 0;
		uint	u_type_channels	= 0;
		uint	u_type_size		= 0;

		for (usize i = 0; i < CountOf( s_aTexFormats ); ++i)
		{
			if ( eFormat == s_aTexFormats[i].eFormat ) {
				u_fmt_channels = s_aTexFormats[i].uChannels;
				break;
			}
		}

		if ( u_fmt_channels == 0 )
			return false;

		for (usize i = 0; i < CountOf( s_aTexDataType ); ++i)
		{
			if ( eType == s_aTexDataType[i].eType ) {
				u_type_channels	= s_aTexDataType[i].uChannels;
				u_type_size		= s_aTexDataType[i].uSize;
				break;
			}
		}

		if ( u_type_size == 0 )
			return false;

		if ( u_type_channels != 0 )
		{
			if ( u_type_channels != u_fmt_channels )
				return false;
			else {
				uBPP = u_type_size;
				return true;
			}
		}

		uBPP = u_fmt_channels * u_type_size;
		return true;
	}
	
/*
=================================================
	возвращает информацию о внутреннем формате
	текстуры или рендер буфера
=================================================
*/
	bool GLTexFormatInfo::GetIntegnalFormatInfo(gl_texture::type eTarget, gl_tex_iformat::type eIFormat,
												GLInternalFormatInfo &sInfo)
	{
		typedef GLInternalFormatInfo	e_comp;

		GLint	i_temp	= 0;
		bool	b_res	= true;
		
		GL_CALL_R( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_SUPPORTED, 1, &i_temp ) );
		if ( i_temp == GL_FALSE ) {
			sInfo = GLInternalFormatInfo();
			return false;
		}

		sInfo.eInternalFormat	= eIFormat;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_SAMPLES, 1, (GLint *) &sInfo.uMaxSamples ), b_res );

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_PREFERRED, 1, &i_temp ), b_res );
		sInfo.ePreferredIFormat = (gl_tex_iformat::type) i_temp;
		
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_RED_SIZE,	1,	(GLint *)& sInfo.aCompSize[e_comp::R] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_GREEN_SIZE,	1,	(GLint *)& sInfo.aCompSize[e_comp::G] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_BLUE_SIZE,	1,	(GLint *)& sInfo.aCompSize[e_comp::B] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_ALPHA_SIZE,	1,	(GLint *)& sInfo.aCompSize[e_comp::A] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_DEPTH_SIZE,	1,	(GLint *)& sInfo.aCompSize[e_comp::DEPTH] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_STENCIL_SIZE, 1,(GLint *)& sInfo.aCompSize[e_comp::STENCIL] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_SHARED_SIZE, 1,	(GLint *)& sInfo.aCompSize[e_comp::SHARED] ), b_res );

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_RED_TYPE,	1,	(GLint *)& sInfo.aCompType[e_comp::R] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_GREEN_TYPE,	1,	(GLint *)& sInfo.aCompType[e_comp::G] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_BLUE_TYPE,	1,	(GLint *)& sInfo.aCompType[e_comp::B] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_ALPHA_TYPE,	1,	(GLint *)& sInfo.aCompType[e_comp::A] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_INTERNALFORMAT_DEPTH_TYPE,	1,	(GLint *)& sInfo.aCompType[e_comp::DEPTH] ), b_res );
		sInfo.aCompType[e_comp::STENCIL]	= gl_tex_component::INT;
		sInfo.aCompType[e_comp::SHARED]		= gl_tex_component::NONE;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_MAX_WIDTH,		1, (GLint *) &sInfo.vDimensions[0] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_MAX_HEIGHT,	1, (GLint *) &sInfo.vDimensions[1] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_MAX_DEPTH,		1, (GLint *) &sInfo.vDimensions[2] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_MAX_LAYERS,	1, (GLint *) &sInfo.vDimensions[3] ), b_res );
		
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_COLOR_COMPONENTS,		1, &i_temp ), b_res );
		sInfo.sColor.bAvailable		= i_temp == GL_TRUE;
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_COLOR_RENDERABLE,		1, &i_temp ), b_res );
		sInfo.sColor.bRenderable	= i_temp == GL_TRUE;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_DEPTH_COMPONENTS,		1, &i_temp ), b_res );
		sInfo.sDepth.bAvailable		= i_temp == GL_TRUE;
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_DEPTH_RENDERABLE,		1, &i_temp ), b_res );
		sInfo.sDepth.bRenderable	= i_temp == GL_TRUE;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_STENCIL_COMPONENTS,	1, &i_temp ), b_res );
		sInfo.sStencil.bAvailable	= i_temp == GL_TRUE;
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_STENCIL_RENDERABLE,	1, &i_temp ), b_res );
		sInfo.sStencil.bRenderable	= i_temp == GL_TRUE;

		
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_FRAMEBUFFER_RENDERABLE,	1, &i_temp ), b_res );
		sInfo.eFramebufferRenderable		= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_FRAMEBUFFER_RENDERABLE_LAYERED,	1, &i_temp ), b_res );
		sInfo.eFramebufferRenderableLayered	= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_FRAMEBUFFER_BLEND,	1, &i_temp ), b_res );
		sInfo.eFramebufferBlend				= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_READ_PIXELS,	1, &i_temp ), b_res );
		sInfo.bReadPixels	= i_temp == GL_TRUE;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_MIPMAP,	1, &i_temp ), b_res );
		sInfo.bMipmaps		= i_temp == GL_TRUE;


		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_MANUAL_GENERATE_MIPMAP,	1, &i_temp ), b_res );
		sInfo.eManualGenerateMipmaps	= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_AUTO_GENERATE_MIPMAP,	1, &i_temp ), b_res );
		sInfo.eAutoGenerateMipmaps		= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_COLOR_ENCODING,	1, &i_temp ), b_res );
		sInfo.eColorEncoding			= (gl_color_encoding::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_SRGB_READ,	1, &i_temp ), b_res );
		sInfo.eSRGBRead					= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_SRGB_WRITE,	1, &i_temp ), b_res );
		sInfo.eSRGBWrite				= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_FILTER,	1, &i_temp ), b_res );
		sInfo.eFilter					= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_TEXTURE_SHADOW,	1, &i_temp ), b_res );
		sInfo.eTextureShadow			= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_TEXTURE_GATHER,	1, &i_temp ), b_res );
		sInfo.eTextureGather			= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_TEXTURE_GATHER_SHADOW,	1, &i_temp ), b_res );
		sInfo.eTextureGatherShadow		= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_SHADER_IMAGE_LOAD,	1, &i_temp ), b_res );
		sInfo.eShaderImageLoad			= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_SHADER_IMAGE_STORE,	1, &i_temp ), b_res );
		sInfo.eShaderImageStore			= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_SHADER_IMAGE_ATOMIC,	1, &i_temp ), b_res );
		sInfo.eShaderImageAtomic		= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_IMAGE_TEXEL_SIZE,	1, (GLint *) &sInfo.uTexelSize ), b_res );
			
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_IMAGE_COMPATIBILITY_CLASS,	1, &i_temp ), b_res );
		sInfo.eImageClass				= (gl_image_class::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_IMAGE_PIXEL_FORMAT,	1, &i_temp ), b_res );
		sInfo.ePixelFormat				= (gl_pixel_format::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_IMAGE_PIXEL_TYPE,		1, &i_temp ), b_res );
		sInfo.ePixelType				= (gl_pixel::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_IMAGE_FORMAT_COMPATIBILITY_TYPE,	1, &i_temp ), b_res );
		sInfo.eImageFormatCompatibility	= (gl_img_fmt_compatibility::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST,	1, &i_temp ), b_res );
		sInfo.eSimultaneousTextureAndDepthTest		= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST,	1, &i_temp ), b_res );
		sInfo.eSimultaneousTextureAndStencilTest	= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE,	1, &i_temp ), b_res );
		sInfo.eSimultaneousTextureAndDepthWrite		= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE, 1, &i_temp ), b_res );
		sInfo.eSimultaneousTextureAndStencilWrite	= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_TEXTURE_COMPRESSED,	1, &i_temp ), b_res );
		sInfo.bCompressed		= i_temp == GL_TRUE;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_TEXTURE_COMPRESSED_BLOCK_WIDTH,	1, (GLint *) &sInfo.vCompressedBlockDim[0] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT,	1, (GLint *) &sInfo.vCompressedBlockDim[1] ), b_res );
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_TEXTURE_COMPRESSED_BLOCK_SIZE,		1, (GLint *) &sInfo.uCompressedBlockSize ), b_res );
		
		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_CLEAR_BUFFER,	1, &i_temp ), b_res );
		sInfo.eClearBuffer			= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_TEXTURE_VIEW,	1, &i_temp ), b_res );
		sInfo.eTextureView			= (gl_support::type) i_temp;

		GL_CALL_BA( glGetInternalformativ( eTarget, eIFormat, GL_VIEW_COMPATIBILITY_CLASS,	1, &i_temp ), b_res );
		sInfo.eTexViewClass			= (gl_tex_view_class::type) i_temp; 

		return b_res;
	}

//-------------------------------------------------------------------

}	// GLShell
}	// UX_STL